home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / expr.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  13KB  |  630 lines

  1. /* expr  - expression evaluator for shell    Author: Peter S. Housel */
  2.  
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <stdio.h>
  6.  
  7. extern char *malloc(     /* size_t nbytes */ );
  8.  
  9. struct value {
  10.   long numval;            /* numeric value */
  11.   int nf_valid;            /* "numeric value field valid" flag */
  12.   char *strval;            /* string value */
  13. };
  14.  
  15. #define    numresult(valp,number)             \
  16.     (((valp)->nf_valid = 1),         \
  17.      ((valp)->strval = NULL),        \
  18.      ((valp)->numval = (number)))
  19.  
  20. void invalid(     /* char *err */ );
  21. char *strvalue(     /* struct value *valp */ );
  22. int numvalue(     /* struct value *valp */ );
  23. char *strsave(     /* char *string */ );
  24. void expr1(     /* struct value *valp */ ),
  25.  expr2(     /* struct value *valp */ ),
  26.  expr3(     /* struct value *valp */ ),
  27.  expr4(     /* struct value *valp */ ),
  28.  expr5(     /* struct value *valp */ ),
  29.  expr6(     /* struct value *valp */ ),
  30.  expr7(     /* struct value *valp */ );
  31. void docolon(     /* value *match, *pattern */ );
  32.  
  33. char *progname;
  34. char **argp;
  35. char NUMARG[] = "numeric argument required";
  36.  
  37. main(argc, argv)
  38. int argc;
  39. char *argv[];
  40. {
  41.   struct value val0;
  42.  
  43.   progname = argv[0];
  44.   argp = &argv[1];
  45.   expr1(&val0);
  46.   if (*argp != NULL) invalid("syntax error");
  47.   (void) puts(strvalue(&val0));
  48.   exit(nullz(&val0));
  49. }
  50.  
  51. /* Yet Another recursive descent parser. */
  52. void expr1(valp)
  53. struct value *valp;
  54. {
  55.   struct value val1;
  56.  
  57.   expr2(valp);
  58.  
  59.   while (*argp != NULL) {
  60.     if (strcmp(*argp, "|") == 0) {
  61.         ++argp;
  62.         expr2(&val1);
  63.         if (nullz(valp))
  64.             *valp = val1;
  65.         else;        /* return the first arg (already in *valp) */
  66.     } else
  67.         break;
  68.   }
  69. }
  70.  
  71. void expr2(valp)
  72. struct value *valp;
  73. {
  74.   struct value val1;
  75.  
  76.   expr3(valp);
  77.  
  78.   while (*argp != NULL) {
  79.     if (strcmp(*argp, "&") == 0) {
  80.         ++argp;
  81.         expr3(&val1);
  82.         if (nullz(valp) && nullz(&val1))
  83.             numresult(valp, 0);
  84.         else;        /* return the first arg (already in *valp) */
  85.     } else
  86.         break;
  87.   }
  88. }
  89.  
  90. /* Save source code lines but not object code, unfortunately. */
  91.  
  92. #define RELOP(OP)                        \
  93.     ++argp;                        \
  94.     expr4(&val1);                        \
  95.     if(numvalue(valp) && numvalue(&val1))            \
  96.        numresult(valp, valp->numval OP val1.numval);    \
  97.     else                            \
  98.        numresult(valp, strcmp(strvalue(valp), strvalue(&val1)) OP 0);
  99.  
  100. void expr3(valp)
  101. struct value *valp;
  102. {
  103.   struct value val1;
  104.  
  105.   expr4(valp);
  106.  
  107.   while (*argp != NULL) {
  108.     if (strcmp(*argp, "<") == 0) {
  109.         RELOP(<)
  110.     } else if (strcmp(*argp, "<=") == 0) {
  111.         RELOP(<=)
  112.     } else if (strcmp(*argp, "=") == 0) {
  113.         RELOP(==)
  114.     } else if (strcmp(*argp, "!=") == 0) {
  115.         RELOP(!=)
  116.     } else if (strcmp(*argp, ">=") == 0) {
  117.         RELOP(>=)
  118.     } else if (strcmp(*argp, ">") == 0) {
  119.         RELOP(>)
  120.     } else
  121.         break;
  122.   }
  123. }
  124.  
  125. #define BINOP(NEXT,OP)                        \
  126.     ++argp;                        \
  127.     NEXT(&val1);                        \
  128.     if(!numvalue(valp) || !numvalue(&val1))        \
  129.        invalid(NUMARG);                    \
  130.     else                            \
  131.        numresult(valp, valp->numval OP val1.numval);    \
  132.  
  133. void expr4(valp)
  134. struct value *valp;
  135. {
  136.   struct value val1;
  137.  
  138.   expr5(valp);
  139.  
  140.   while (*argp != NULL) {
  141.     if (strcmp(*argp, "+") == 0) {
  142.         BINOP(expr5, +)
  143.     } else if (strcmp(*argp, "-") == 0) {
  144.         BINOP(expr5, -)
  145.     } else
  146.         break;
  147.   }
  148. }
  149.  
  150. void expr5(valp)
  151. struct value *valp;
  152. {
  153.   struct value val1;
  154.  
  155.   expr6(valp);
  156.  
  157.   while (*argp != NULL) {
  158.     if (strcmp(*argp, "*") == 0) {
  159.         BINOP(expr6, *)
  160.     } else if (strcmp(*argp, "/") == 0) {
  161.         ++argp;
  162.         expr6(&val1);
  163.         if (!numvalue(valp) || !numvalue(&val1))
  164.             invalid(NUMARG);
  165.         else {
  166.             if (val1.numval == 0) invalid("division by zero");
  167.             numresult(valp, valp->numval / val1.numval);
  168.         }
  169.     } else if (strcmp(*argp, "%") == 0) {
  170.         ++argp;
  171.         expr6(&val1);
  172.         if (!numvalue(valp) || !numvalue(&val1))
  173.             invalid(NUMARG);
  174.         else {
  175.             if (val1.numval == 0) invalid("division by zero");
  176.             numresult(valp, valp->numval % val1.numval);
  177.         }
  178.     } else
  179.         break;
  180.   }
  181. }
  182.  
  183. void expr6(valp)
  184. struct value *valp;
  185. {
  186.   struct value val1;
  187.  
  188.   expr7(valp);
  189.  
  190.   while (*argp != NULL) {
  191.     if (strcmp(*argp, ":") == 0) {
  192.         ++argp;
  193.         expr7(&val1);
  194. #ifndef NOCOLON
  195.         docolon(valp, &val1);
  196. #else
  197.         valp->nf_valid = 0;
  198.         valp->strval = NULL;
  199. #endif
  200.     } else
  201.         break;
  202.   }
  203. }
  204.  
  205. void expr7(valp)
  206. struct value *valp;
  207. {
  208.   if (*argp == NULL)
  209.     invalid("missing argument(s)");
  210.   else if (strcmp(*argp, "(") == 0) {
  211.     ++argp;
  212.     expr1(valp);
  213.     if (strcmp(*argp++, ")") != 0) invalid("unbalanced parentheses");
  214.   } else {
  215.     valp->nf_valid = 0;
  216.     valp->strval = *argp++;
  217.   }
  218. }
  219.  
  220. /* Return 1 if the argument is zero (numeric) or null (string */
  221. int nullz(valp)
  222. struct value *valp;
  223. {
  224.   if (numvalue(valp)) return(valp->numval == 0);
  225.  
  226.   return(strlen(strvalue(valp)) == 0);
  227. }
  228.  
  229. /* Return 1 if the argument is a valid number, insuring that the nf_valid
  230.  * and numval fields are set properly. Does the string-to-number
  231.  * conversion if nf_valid is false.
  232.  */
  233. int numvalue(valp)
  234. struct value *valp;
  235. {
  236.   register char *p;
  237.   int sign = 0, digits = 0;
  238.   unsigned long num = 0;
  239.  
  240.   if (valp->nf_valid) return 1;
  241.  
  242.   if ((p = valp->strval) == NULL) return 0;
  243.  
  244.   if (*p == '-') {
  245.     ++p;
  246.     sign = 1;
  247.   }
  248.   while (isdigit(*p)) {
  249.     num = num * 10 + (*p++ - '0');
  250.     digits = 1;
  251.   }
  252.  
  253.   if (!digits || *p != '\0') return 0;
  254.  
  255.   valp->numval = sign ? -num : num;
  256.   valp->nf_valid = 1;
  257.   return 1;
  258. }
  259.  
  260. /* Return the string value of the given argument. If there is only a
  261.  * numeric value, convert it to a string
  262.  */
  263. char *strvalue(valp)
  264. struct value *valp;
  265. {
  266.   char numbuf[30];
  267.   register char *p;
  268.   unsigned long num;
  269.   int sign = 0;
  270.  
  271.   if (!valp->nf_valid) return(valp->strval != NULL) ? valp->strval : "";
  272.  
  273.   p = numbuf + sizeof numbuf;
  274.   *--p = '\0';
  275.  
  276.   if (valp->numval < 0) {
  277.     num = -(valp->numval);
  278.     sign = 1;
  279.   } else
  280.     num = valp->numval;
  281.  
  282.   do {
  283.     *--p = '0' + (num % 10);
  284.     num /= 10;
  285.   } while (num);
  286.  
  287.   if (sign) *--p = '-';
  288.  
  289.   return(valp->strval = strsave(p));
  290. }
  291.  
  292. /* Save the given string in its own allocated memory and return a pointer
  293.  * to that memory.
  294.  */
  295. char *strsave(string)
  296. char *string;
  297. {
  298.   char *p;
  299.  
  300.   if ((p = malloc(strlen(string) + 1)) == NULL) invalid("out of memory");
  301.  
  302.   (void) strcpy(p, string);
  303.  
  304.   return p;
  305. }
  306.  
  307. /* Print error message and exit. */
  308. void invalid(err)
  309. char *err;
  310. {
  311.   (void) fputs(progname, stderr);
  312.   (void) fputs(": ", stderr);
  313.   (void) fputs(err, stderr);
  314.   (void) putc('\n', stderr);
  315.   exit(2);
  316. }
  317.  
  318. #ifndef NOCOLON
  319.  
  320. #include <limits.h>
  321.  
  322. #define RMIN        (UCHAR_MAX-8)    /* >= reserved as opcodes */
  323. #define RESC        (UCHAR_MAX-8)    /* for escaping opcodes */
  324. #define RDOT        (UCHAR_MAX-7)    /* match any character */
  325. #define ROPEN        (UCHAR_MAX-6)    /* opening \( */
  326. #define RCLOSE        (UCHAR_MAX-5)    /* closing \) */
  327. #define RSTAR        (UCHAR_MAX-4)    /* Kleene closure */
  328. #define RCLASS        (UCHAR_MAX-3)    /* character class */
  329. #define RBACK        (UCHAR_MAX-2)    /* \digit reference */
  330. #define REND        (UCHAR_MAX-1)    /* end of program */
  331.  
  332. #define    RABEGIN        0x01    /* match anchored at BOL (^) */
  333. #define RAEND        0x02    /* match anchored at EOL ($) */
  334. #define RSELECT        0x04    /* \(...\) selection op used */
  335.  
  336. #define PROGLENGTH    1024    /* bytes reserved for r-programs */
  337.  
  338. #define    CLASS_BYTES    ((CHAR_MAX - CHAR_MIN) / CHAR_BIT)
  339.  
  340. unsigned char rprogram[PROGLENGTH];    /* regexp program storage */
  341. unsigned int rflags = RABEGIN;    /* regexp program context */
  342.  
  343. char *rbegins[10];        /* pointers to \( beginnings */
  344. char *rends[10];        /* pointers to \) endings */
  345. int rlevel;            /* \(...\) level */
  346.  
  347. void rcomp(     /* char *regexp */ );
  348. void rmatch(     /* char *str */ );
  349. char *rtry(     /* char *str, unsigned char **pcp */ );
  350. char *tryone(     /* char *str, unsigned char **pcp */ );
  351.  
  352. /* Compile the regexp, match it against the string, and return the
  353.  * proper result (a string if \(...\) used, and the match length otherwise.
  354.  */
  355. void docolon(match, pattern)
  356. struct value *match, *pattern;
  357. {
  358.   rcomp(strvalue(pattern));
  359.  
  360.   rmatch(strvalue(match));
  361.  
  362.   if (rflags & RSELECT) {
  363.     match->nf_valid = 0;
  364.     if (rends[0] == rbegins[0] || rends[1] == NULL) {
  365.         match->strval = NULL;
  366.     } else {
  367.         *(rends[1]) = '\0';    /* semi-nasty */
  368.         match->strval = rbegins[1];
  369.     }
  370.   } else {
  371.     numresult(match, rends[0] - rbegins[0]);
  372.   }
  373. }
  374.  
  375. /* Compile an ed(1)-syntax regular-expression into the rprogram[] array. */
  376. void rcomp(regexp)
  377. register char *regexp;
  378. {
  379.   char c;            /* current regexp character */
  380.   char first, last;        /* limits of character class */
  381.   unsigned char *starable;    /* last "starable" variable */
  382.   unsigned char *rpc;        /* pointer to next program sto